package com.zifan.sever.filter;

import com.zifan.sever.bean.Menu;
import com.zifan.sever.bean.Role;
import com.zifan.sever.service.IMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import java.util.Collection;
import java.util.List;

/**
 * FilterInvocationSecurityMetadataSource 筛选器调用安全性元数据源
 * @author Zifan
 * @date 2021年04月11日18:20
 */
@Component
public class CustomFilter implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private IMenuService menuService;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        //获取请求的url
        String requestUrl = ((FilterInvocation) o).getRequestUrl();
        List<Menu> menus = menuService.getMenusWithRole();
        /**
         * 这里的意思是，
         * 首先，拿到了请求的 requestUrl url
         * 上面拿到了个菜单列表。列表中的菜单是带有角色列表的，
         * 这个角色列表的意思是，这个菜单能被哪些角色看到。
         * 然后就是下面的循环了
         * 对这整个菜单列表循环，循环的目的是这样的。
         * 通过antPathMatcher来做匹配，哪俩进行匹配呢？
         * 循环中的meun里面的url（也就是我们规定的该菜单的请求url） 与 请求的url
         * 这俩进行匹配，如果匹配上了
         * 就意味这我们的这个请求路径就是个菜单路径，并且就是这个菜单的路径
         * 然后，因为之前我们不仅仅查询的是菜单列表，每个菜单时带有roles的
         * 匹配上了之后，就把这里菜单里面的roles拿出来，把role的name变成一个string类型的数组
         * 这里就用到了，java8的流式编程与lamada表达式
         * 拿到这个数组之后，这里就有点迷惑了 先打个 todo
         * 使用SecurityConfig.createList方法把那个数组扔进去
         * 扔进去的目的是，下一个过滤去CustomUrlDecisionManager实现了AccessDecisionManager接口
         * 这个接口有一个方法decide（决定），该方法有个入参Collection<ConfigAttribute> configAttributes
         * 这个configAttributes里面就是我们放入的这个string类型的数组！！
         *
         */
        for (Menu menu : menus) {
            //判断请求url与菜单角色是否匹配
            if (antPathMatcher.match(menu.getUrl(),requestUrl)){
                //如果匹配上了，就把该菜单下的角色列表拿出来，转换成角色名,并形成一个数组，
                String[] strings = menu.getRoles().stream().map(Role::getName).toArray(String[]::new);
                // 然后执行SecurityConfig.createList(strings);
                return SecurityConfig.createList(strings);
            }
        }

        //没有匹配的url默认登陆即可访问
        return SecurityConfig.createList("ROLE_LOGIN");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return false;
    }
}
